import cv2
import platform
from PIL import Image, ImageTk
import tkinter as tk
from tkinter import messagebox


def open_camera(camera_index):
    """
    打开指定索引的摄像头，并在新窗口中显示实时视频流。
    """
    # 根据操作系统选择合适的OpenCV后端
    system = platform.system()
    if system == "Windows":
        backend = cv2.CAP_DSHOW
    elif system == "Darwin":  # macOS
        backend = cv2.CAP_AVFOUNDATION
    else:  # Linux和其他系统
        backend = cv2.CAP_V4L2

    cap = cv2.VideoCapture(camera_index, backend)

    if not cap.isOpened():
        tk.messagebox.showerror("错误", f"无法打开摄像头 {camera_index}")
        return

    camera_window = tk.Toplevel()  # 创建新的顶级窗口
    camera_window.title(f"摄像头 {camera_index}")  # 设置窗口标题
    camera_window.protocol("WM_DELETE_WINDOW", lambda: close_camera(cap, camera_window))

    camera_label = tk.Label(camera_window)  # 创建用于显示视频帧的标签
    camera_label.pack(padx=10, pady=10)

    # 获取摄像头的原始分辨率
    original_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    original_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    
    # 设置合适的显示大小
    if original_width > 0 and original_height > 0:
        # 保持宽高比，最大宽度640
        max_width = 640
        scale = min(max_width / original_width, 1.0)
        desired_width = int(original_width * scale)
        desired_height = int(original_height * scale)
    else:
        desired_width = 480
        desired_height = 270

    def show_frame():
        """
        捕获摄像头的当前帧，并在标签上显示。
        """
        if not cap.isOpened():
            return
            
        ret, frame = cap.read()  # 读取一帧视频
        if ret and frame is not None:
            try:
                resized_frame = cv2.resize(frame, (desired_width, desired_height))
                frame_rgb = cv2.cvtColor(resized_frame, cv2.COLOR_BGR2RGB)  # 将BGR颜色转换为RGB
                img = Image.fromarray(frame_rgb)  # 将帧转换为Image对象
                imgtk = ImageTk.PhotoImage(image=img)  # 将Image对象转换为PhotoImage对象
                camera_label.imgtk = imgtk  # 避免垃圾回收
                camera_label.configure(image=imgtk)  # 更新标签的图像
                camera_label.after(10, show_frame)  # 10ms后再次调用此函数
            except Exception as e:
                print(f"显示帧时出错: {e}")
                camera_label.after(100, show_frame)
        else:
            camera_label.after(100, show_frame)

    def close_camera(cap, window):
        """关闭摄像头和窗口"""
        if cap.isOpened():
            cap.release()
        window.destroy()

    show_frame()  # 开始显示视频流
